﻿using Newtonsoft.Json;
using RestSharp;
using System;
using System.Collections.Generic;
using ZZDingTalkSDK.ZZDingTalkRequest.Common;
using ZZDingTalkSDK.ZZDingTalkResponse.common;

namespace ZZDingTalkSDK
{
    public class ZZDingTalkService : IZZDingTalkService
    {
        private static RestClient _client;

        /// <summary>
        /// zzd访问接口域名
        /// </summary>
        /// http://httpbin.org/anything # Proxy
        /// https://openplatform-pro.ding.zj.gov.cn # Prod
        private readonly string _domain_name = "https://openplatform-pro.ding.zj.gov.cn";

        private static string _app_key;
        private static string _app_secret_key;

        public ZZDingTalkService(string appKey, string appSecretKey)
        {
            _client = new RestClient(_domain_name);
            _app_key = appKey;
            _app_secret_key = appSecretKey;
        }

        public ZZDingTalkResponse<T> Get<T>(IZZDRequest<T> request)
        {
            return Excute(request, Method.Get);
        }

        public ZZDingTalkResponse<T> Post<T>(IZZDRequest<T> request)
        {
            return Excute(request, Method.Post);
        }

        /// <summary>
        /// 上传文件专用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="file"></param>
        /// <returns></returns>
        public ZZDingTalkResponse<T> UploadFile<T>(IZZDRequest<T> request, string filePath, string fileArgName = "media")
        {
            var paramJoson = JsonConvert.SerializeObject(request);
            IDictionary<string, object> param = JsonConvert.DeserializeObject<Dictionary<string, object>>(paramJoson);

            var headers = BuildHeaders(Method.Post.ToString().ToUpper(), request.GetApiName(), param);

            var restRequest = new RestRequest(request.GetApiName(), Method.Post);

            foreach (var kv in headers)
            {
                restRequest.AddHeader(kv.Key, kv.Value);
            }

            foreach (var kv in param)
            {
                restRequest.AddParameter(kv.Key, kv.Value, ParameterType.GetOrPost);
            }
            restRequest.AddFile(fileArgName, filePath);
            var result = _client.Execute(restRequest);
            if (result.IsSuccessful)
            {
                var content = result.Content ?? string.Empty;
                var response = JsonConvert.DeserializeObject<ZZDingTalkResponse<T>>(content);
                if (response != null)
                {
                    response.ResponseContent = result.Content ?? string.Empty;
                    return response;
                }
            }
            var ErrorResponse = Activator.CreateInstance<ZZDingTalkResponse<T>>();
            ErrorResponse.ResponseContent = result.Content ?? string.Empty;
            return ErrorResponse;
        }

        private IDictionary<string, string> BuildHeaders(string method, string apiName, IDictionary<string, object> param)
        {
            var timestamp = ZZDingTalkHelper.GetTimestamp();
            var nonceStr = ZZDingTalkHelper.GetRandomString();
            IDictionary<string, string> headers = new Dictionary<string, string>();
            headers.Add("X-Hmac-Auth-IP", "127.0.0.1");
            headers.Add("X-Hmac-Auth-MAC", "");
            headers.Add("X-Hmac-Auth-Timestamp", timestamp);
            headers.Add("X-Hmac-Auth-Version", "1.0");
            headers.Add("X-Hmac-Auth-Nonce", nonceStr);
            headers.Add("apiKey", _app_key);
            var queryStr = ZZDingTalkHelper.ParamToQueryString(param);
            string signStr = $"{method}\n{timestamp}\n{nonceStr}\n{apiName}";
            if (queryStr != null)
            {
                signStr += $"\n{queryStr}";
            }
            var signature = ZZDingTalkHelper.SHA256(_app_secret_key, signStr);
            headers.Add("X-Hmac-Auth-Signature", signature);
            return headers;
        }

        private ZZDingTalkResponse<T> Excute<T>(IZZDRequest<T> request, Method method)
        {
            var paramJoson = JsonConvert.SerializeObject(request);
            IDictionary<string, object> param = JsonConvert.DeserializeObject<Dictionary<string, object>>(paramJoson);

            var headers = BuildHeaders(method.ToString().ToUpper(), request.GetApiName(), param);

            var restRequest = new RestRequest(request.GetApiName(), method);

            foreach (var kv in headers)
            {
                restRequest.AddHeader(kv.Key, kv.Value);
            }

            foreach (var kv in param)
            {
                restRequest.AddParameter(kv.Key, kv.Value, ParameterType.GetOrPost);
            }

            var result = _client.Execute(restRequest);

            if (result.IsSuccessful)
            {
                var content = result.Content ?? string.Empty;
                var response = JsonConvert.DeserializeObject<ZZDingTalkResponse<T>>(content);
                if (response != null)
                {
                    response.ResponseContent = result.Content ?? string.Empty;
                    return response;
                }
            }
            var ErrorResponse = Activator.CreateInstance<ZZDingTalkResponse<T>>();
            ErrorResponse.ResponseContent = result.Content ?? string.Empty;
            return ErrorResponse;
        }
    }
}